package edu.hawaii.duedates.lender;

import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;

import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.lang.reflect.Field;

/**
 * Test class for UhManoaLibraryQuery.
 * 
 * @author Aric West
 * @author Daniel Tian
 *
 */
public class TestUhManoaLibrary {
  private final UhManoaLibrary library;
  private final String uhmid; // required to pass PMD
  private final String uhmpass; // required to pass PMD
  
  /**
   * Constructor. Creates an instance of UhManoaLibraryQuery.
   */
  public TestUhManoaLibrary() {
    this.library = new UhManoaLibrary();
    this.uhmid = "uhmid";
    this.uhmpass = "uhmpass";
  }

  /** 
   * Testing equality.
   * 
   * @throws Exception Throws on all non-runtime exceptions.
   */
  @Test
  public void testEquality() throws Exception {
    UhManoaLibrary library2;
    UhManoaLibrary library3;
    
    // reflexivity
    library2 = this.library;
    assertTrue("Testing reflexivity (a = a)", this.library.equals(library2));
    
    // symmetry
    library2 = new UhManoaLibrary();
    assertEquals("Testing symmetry (a = b) = (b = a)",
      this.library.equals(library2), library2.equals(this.library));
    
    // transitivity
    library3 = new UhManoaLibrary();
    assertEquals("Testing transitivity (a = b)", this.library, library2);
    assertEquals("Testing transitivity (b = c)", library2, library3);
    assertEquals("Testing transitivity (a = c)", this.library, library3);
    
    // hash code, change the item list for library3 to contain one item first
    List<BorrowedItem> itemList = new ArrayList<BorrowedItem>();
    itemList.add(new BorrowedItem("test", "01-02-2008"));
    
    Field field = library3.getClass().getSuperclass().getDeclaredField("itemList");
    field.setAccessible(true);
    field.set(library3, itemList);
    
    assertEquals("Testing hash code equals", this.library.hashCode(), library2.hashCode());
    assertNotSame("Testing hash code not equals", this.library.hashCode(), library3.hashCode());
  }
  
  /**
   * Test getLenderName method.
   */
  @Test
  public void testGetLenderNameMethod() {
    assertEquals("Testing correct lender name", "University of Hawaii at Manoa",
      library.getLenderName());
  }
  
  /**
   * Test logging in and getting the item list, sorted item list, and item list within a certain 
   * date.
   * 
   * @throws Exception Throws on all non-runtime exceptions.
   */
  @Test
  public void testGetBorrowedItems() throws Exception {
    if (System.getProperty(uhmid) == null || System.getProperty(uhmpass) == null) {
      throw new Exception("You must provide a test account with books checked out by passing " +
        "command-line arguments as \"-Duhmid=12345678 -Duhmpass=Test\"");
    }
    
    // test normal login and get item list
    this.library.setLoginFields(System.getProperty(uhmid), System.getProperty(uhmpass));
    this.library.logIn();
    this.library.queryBorrowedItems();
    assertTrue("Item list is not empty (test account must have books checked out)",
      library.getItemList().size() > 0);
    
    // test sorting item list
    List<BorrowedItem> itemList = new ArrayList<BorrowedItem>();
    
    for (BorrowedItem item : library.getItemList()) {
      itemList.add(item);
    }
    
    Collections.sort(itemList);
    this.library.sort();
    assertEquals("Item list is sorted", itemList, this.library.getItemList());
    
    // test getting item list within date
    Calendar withinDate = Calendar.getInstance();
    withinDate.add(Calendar.DAY_OF_MONTH, 7); // set calendar date to 1 week ahead of today
    
    List<BorrowedItem> itemListWithin = new ArrayList<BorrowedItem>();
    
    for (BorrowedItem item : itemList) {
      if (item.getDueDate().before(withinDate)) {
        itemListWithin.add(item);
      }
    }
    
    assertEquals("Item list within date is correct", itemListWithin,
      this.library.getItemListWithinDate(withinDate));
  }
  
  /**
   * Test not setting the login parameters throws LogInException.
   * 
   * @throws Exception When the login parameters are not set.
   */
  @Test(expected = LogInException.class)
  public void testNoLoginCredentials() throws Exception {
    this.library.logIn();
  }
  
  /**
   * Test invalid login parameters throws LogInException.
   * 
   * @throws Exception When the login values are not correct and the user is not logged in.
   */
  @Test(expected = LogInException.class)
  public void testBadLoginCredentials() throws Exception {
    library.setLoginFields("12345678", "none");
    library.logIn();
  }
  
  /**
   * Test invalid URL throws LogInException.
   * 
   * @throws Exception When the URL of the page does not lead to a website (404 error).
   */
  @Test(expected = LogInException.class)
  public void testCantGetLoginPage() throws Exception {
    Field field = library.getClass().getSuperclass().getDeclaredField("url");
    field.setAccessible(true);
    
    field.set(library, "http://0.0.0.0");
    this.library.setLoginFields(System.getProperty(uhmid), System.getProperty(uhmpass));
    this.library.logIn();
  }
  
  /**
   * Test URL leading to page with the wrong formatting throws LogInException.
   * 
   * @throws Exception When the page is not in the correct format to be parsed.
   */
  @Test(expected = LogInException.class)
  public void testCantParseLoginPage() throws Exception {
    Field field = this.library.getClass().getSuperclass().getDeclaredField("url");
    field.setAccessible(true);
    
    field.set(this.library, "http://www.google.com/");
    this.library.setLoginFields(System.getProperty(uhmid), System.getProperty(uhmpass));
    this.library.logIn();
  }
  
  /**
   * Test toString method.
   */
  @Test
  public void testToStringMethod() {
    assertEquals("Testing toString method",
                 "University of Hawaii at Manoa has 0 items checked out.", library.toString());
  }
}
